package com.leigq.www.mybatisplusstudy.config;

import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.ibatis.reflection.MetaObject;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.time.LocalDateTime;
import java.util.Objects;


/**
 * MP自动填充参数
 *
 * @author leiguoqing
 * @date 2021 -10-9 9:03
 */
@Slf4j
@Component
public class MetaObjectHandlerConfig implements MetaObjectHandler {

    /**
     * 插入时填充
     *
     * @param metaObject the meta object
     */
    @Override
    public void insertFill(MetaObject metaObject) {
        log.info("start insert fill ....");
        // 填充创建人id
        this.fillId(metaObject, IdType.CREATOR_ID);

        // 填充创建时间
        this.fillDate(metaObject, DateType.CREATE_TIME);

        // 填充修改人id
        this.fillId(metaObject, IdType.MODIFIER_ID);

        // 填充修改时间
        this.fillDate(metaObject, DateType.UPDATE_TIME);

        // 填充版本号
        this.fillVersion(metaObject);

        // 填充 is_deleted 逻辑删除
        this.fillDeleted(metaObject);
    }


    /**
     * 更新时填充
     *
     * @param metaObject the meta object
     */
    @Override
    public void updateFill(MetaObject metaObject) {
        log.info("start update fill ....");
        // 填充修改人id
        this.fillId(metaObject, IdType.MODIFIER_ID);

        // 填充修改时间
        this.fillDate(metaObject, DateType.UPDATE_TIME);
    }



    /**
     * id类型
     */
    @Getter
    @AllArgsConstructor
    private enum IdType {
        /**
         * 创建人属性名称
         */
        CREATOR_ID("createdBy"),

        /**
         * 修改人属性名称
         */
        MODIFIER_ID("updatedBy"),
        ;

        /**
         * entity 属性名称
         */
        private final String fieldName;
    }


    /**
     * 时间类型
     */
    @Getter
    @AllArgsConstructor
    private enum DateType {
        /**
         * 创建时间属性名称
         */
        CREATE_TIME("createdTime"),

        /**
         * 修改时间属性名称
         */
        UPDATE_TIME("updatedTime"),
        ;

        /**
         * entity 属性名称
         */
        private final String fieldName;
    }


    /**
     * 填充员工id
     *
     * @param metaObject the meta object
     */
    private void fillId(MetaObject metaObject, IdType idType) {
        final boolean hasSetter = metaObject.hasSetter(idType.getFieldName());
        // 有 setter 方法才进行填充
        if (!hasSetter) {
            return;
        }

        final Object fieldVal = this.getFieldValByName(idType.getFieldName(), metaObject);
        // 属性为空才自动填充
        if (Objects.nonNull(fieldVal)) {
            return;
        }

        // 获取登录用户id, 0代表系统，有时数据是定时任务修改的，则为0
        final Long loginUserId = this.getLoginUserId();

        // 填充对应属性
        this.strictInsertFill(metaObject, idType.getFieldName(), Long.class, loginUserId);
    }




    /**
     * 填充时间
     *
     * @param metaObject the meta object
     */
    private void fillDate(MetaObject metaObject, DateType dateType) {
        final boolean hasSetter = metaObject.hasSetter(dateType.getFieldName());
        // 有 setter 方法才进行填充
        if (!hasSetter) {
            return;
        }

        final Object fieldVal = this.getFieldValByName(dateType.getFieldName(), metaObject);
        // 属性为空才自动填充
        if (Objects.nonNull(fieldVal)) {
            return;
        }

        // 填充对应属性
        this.strictInsertFill(metaObject, dateType.getFieldName(), LocalDateTime.class, LocalDateTime.now());
    }


    /**
     * 填充 version.
     *
     * @param metaObject the meta object
     */
    private void fillVersion(MetaObject metaObject) {
        // entity 属性名称
        final String fieldName = "version";

        final boolean hasSetter = metaObject.hasSetter(fieldName);
        // 有 setter 方法才进行填充
        if (!hasSetter) {
            return;
        }

        final Object fieldVal = this.getFieldValByName(fieldName, metaObject);
        // 属性为空才自动填充
        if (Objects.nonNull(fieldVal)) {
            return;
        }

        // 填充对应属性
        this.strictInsertFill(metaObject, fieldName, Integer.class, 1);
    }


    /**
     * 填充 is_deleted
     *
     * @param metaObject the meta Object
     */
    private void fillDeleted(MetaObject metaObject) {
        // entity 属性名称
        final String fieldName = "deleted";

        final boolean hasSetter = metaObject.hasSetter(fieldName);
        // 有 setter 方法才进行填充
        if (!hasSetter) {
            return;
        }

        final Object fieldVal = this.getFieldValByName(fieldName, metaObject);
        // 属性为空才自动填充
        if (Objects.nonNull(fieldVal)) {
            return;
        }

        // 填充对应属性
        this.strictInsertFill(metaObject, fieldName, Boolean.class, false);
    }


    /**
     * 模拟获取登录用户id
     * <br/>
     * 默认为0，代表系统
     *
     * @return the login user id
     */
    private Long getLoginUserId() {
        // 模拟从请求头中获取jwt token
        HttpServletRequest request = ((ServletRequestAttributes) (RequestContextHolder.currentRequestAttributes())).getRequest();
        final String token = request.getHeader("token");

        if (StringUtils.isEmpty(token)) {
            return 0L;
        }
        // 正式环境应该从Redis缓存或者jwt中获取
        return 1L;
    }

}